1.Обзор системы | 2. Мой первый проект | 3. Модель | 4. Представление | 5. Табличное представление | 6. Объектно-реляционное связывание | 7. Контроллеры | 8. Приложение | 9. Расширенные возможности

Глава 2: Мой первый проект OpenXava

Создание нового проекта

Мы будем использовать Eclipse IDE (Eclipse вам необходимо установить самостоятельно, дистрибутив можно сказачать здесь www.eclipse.org), а также сервлет-контейнер Tomcat и базу данных Hypersonic, которые поставляются в составе дистрибутива OpenXava.
Войдите в Eclipse и откройте рабочую область (workspace), которая поставляется вместе с дистрибутивом OpenXava.
Используя стандартный мастер (wizard), Eclipse создадим новый Java проект, назовем его Management. Следующим шагом будет преобразование нашего пока пустого Java проекта в проект OpenXava.
Перейдем в проект OpenXavaTemplate и запустим CreateNewProject.xml, используя Ant. Сделать это можно, нажав правую кнопку мыши на файле CreateNewProject.xml и выбрав пункт > Run as > Ant Build из появившегося меню. Запущенная задача Ant запросит ввести имя проекта, введите Management.
Перейдите в проект Management и нажмите F5 для обновления проекта.
Мы создали новый проект OX и готовы приступить к разработке.
Но сначала нам необходимо сконфигурировать доступ к базе данных.

Конфигурирование базы данных

OpenXava создает JavaEE/J2EE приложение, предназначенное для развертывания в Java Application Server (начиная с версии v2.0 OpenXava приложения также могут развертываться в облегченных контейнерах, таких как Tomcat).
Для работы с базой данной в приложении OX необходимо указать Data Source JNDI, который настраивается как источник данных (data source) в вашем сервере приложений (application server). Описание конфигурирования источника данных (data source) в сервере приложений не входит в задачи данного руководства. Тем не менее, далее вы найдете детальные инструкции по конфигурированию базы данных для запуска нашего первого OX проекта с использоваием включенных в дистрибутив OpenXava сервера приложений Tomcat и базы данных Hypersonic.
Tomcat находится в папке openxava-3.x/tomcat. Убедитесь, что Tomcat остановлен. Затем отредактируйте context.xml в папке conf внутри каталога Tomcat. Добавьте в файл определение JNDI ресурса, соответствующего нашей БД:
 <Resource name="jdbc/ManagementDS" auth="Container" type="javax.sql.DataSource"
 maxActive="20" maxIdle="5" maxWait="10000"
 username="sa" password="" driverClassName="org.hsqldb.jdbcDriver"
 url="jdbc:hsqldb:hsql://localhost:1666"/>
 
В описании ресурса JNDI самый важный параметр name - это имя ресурса, именно на него ссылается OpenXava для доступа к БД, в нашем случае ManagementDS. Аттрибуты driverClassName и url зависят от конкретной базы данных, в примере мы используем Hypersonic.

Ваш первый бизнес-компонент

Нет ничего проще создания нового бизнес-компонента OpenXava. Создание нового бизнес-компонента в OX3 - это просто создание POJO (Plain Java Old Object) Java класса с использованием аннотаций (annotations). В качестве примера начнем с создания класса под названием Warehouse:
  • Начнем с создания пакета: Выберем в структуре проекта папку src, далее по правой кнопке мыши в открывшемся меню выберем New > Package
  • Зададим имя пакета org.openxava.management.model
  • Теперь создадим класс: Перейдем на пакет org.openxava.management.model далее по правой кнопке мыши в открывшемся меню выберем New > Class
  • Зададим имя класса Warehouse
Отредактируем класс:
 package org.openxava.management.model;
 
 import javax.persistence.*;
 import org.openxava.annotations.*;
 
 @Entity
 public class Warehouse {
 
 @Id @Column(length=3) @Required
 private int number;
 
 @Column(length=40) @Required
 private String name;
 
 public int getNumber() {
 return number;
 }
 
 public void setNumber(int number) {
 this.number = number;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 
 }
 
На данный момент класс содержит только описание структуры данных и некоторые аннотации, о которых мы расскажем ниже. В OX такой класс может содержать все данные, которые необходимо знать о бизнес-сущности Warehouse для правильной работы приложению OX. Например, класс может описывать ORM-привязку к таблице базы данных, бизнес-логику, визуальное представление, включая табличное представление данных и т.д.
В действительности данный класс - это Сущность (entity), соответствующая стандарту EJB3. Аннотация @Entity в декларации класса говорит об этом.
В сущности вы можете описывать свойства (properties). Давайте посмотрим, как это делается:
 @Id // 1
 @Column(length=3) // 2
 @Required // 3
 private int number; // 4
 private int getNumber() { // 4
 return number;
 }
 private void setNumber(int number) { // 4
 this.number = number;
 }
 
Давайте разберемся выше представленном описании свойства (номер пункта указан в комментарии):
  1. @Id: Указывает, что данное свойство (переменная-член класса) является частью ключа объекта (key). Ключ (key) -э то уникальный идентификатор объекта и обычно совпадает с первичным ключом (primary key) из таблицы базы данных.
  2. @Column(length= ): Длина данных. Это опциональная аннотация, но указание размера данных является необходимым для граммотного создания пользовательского интерфейса и генерации эффективных таблиц базы данных.
  3. @Required: Указывает, что требуется валидация (проверка) существования данных в данном свойстве перед вставкой или модификацией сущности.
  4. Свойство (property) определяется с использованием стандартного синтаксиса Java. Все типы данных, разрешенные для переменных-членов класса (property) в Java, можно использовать здесь, включая сложные типы, классы JDK, а также любые другие классы.
Более подробно об определении свойств рассказывается в главе Модель (Model).

Создание таблицы в БД

Прежде, чем тестировать приложение, нам необходимо создать таблицу в базе данных. Выполните следующие шаги:
  • Запустите ваш серве базы данных: Из командной строки перейдите в папку openxava-3.x/tomcat/bin и выполните:
    • В Linux/Unix: ./start-hsqldb.sh management-db 1666
    • В Windows: start-hsqldb management-db 1666
  • Создайте таблицу:
    • Откройте на редактирование Management/build.xml. Найдите в файле описание цели updateSchema.
    • Укажите корректное значение для schema.path, в нашем случае “../OpenXavaTest/lib/hsqldb.jar”.
    • Запустите цель updateSchema.
  • Запустите Tomcat. Если сервер уже запущен, обязательно рестартуйте его., Теперь все готово для проверки работоспособности нашего приложения.

Выполнение вашего приложения

Настало время наконец увидеть плоды нашего "титанического" труда. Приступим.
Теперь вы можете потестировать с созданным вами модулем и исследовать его поведение.
Также вы можете преобразовать ваше приложение в JSR-168 портлет. Сделать это можно следующим образом:
  • Выполните цель generatePortlets.
  • Готовый портлет Management.war заберите в папке openxava-3.x/workspace.dist/Management.dist
  • Разверните ваш портлет в портал-сервере (Portal Server).

Автоматизация тестирования

Несмотря на то, что наиболее очевидным и ествественным способом тестирования приложения является ручное повторение действий конечного пользователя - открыть броузер, перейти по ссылке и т.д., гораздо более дальновидным будет автоматизировать тестирование. В этом случае при дальнейшем развитии приложения применением автоматизированных тестов мы гарантируем своевременное обнаружение проблем без дополнительных монотонных усилий с нашей стороны.

Тестирование в OpenXava базируется на использовании JUnit и HtmlUnit. В OpenXava JUnit тесты симулируют поведение реального пользователя, работающего в интернет-броузере. Используя такой подход вы можете выполнять точно такие же тесты, как если бы вы вручную делали это через интернет-броузер. Другое преимущество данного подхода в том, что вы можете оттестировать все слои ваше приложения от пользовательского интерфейса до базы данных.

Рассмотрим, как автоматизировать обычный сценарий ручного тестирования. Тестируя вручную, обычно вы создаете новую запись, выполняете ее поиск, модифицируете ее и в конце вы удаляете эту запись. Попробуем автоматизировать данный сценарий:

Сначала нам необходимо создать пакет для тестовых классов, назовем его org.openxava.management.tests, и добавим туда класс для тестирования Warehouse, назовём его WarehouseTest. Смотрите, что у нас получится:
 package org.openxava.management.tests;
 
 import org.openxava.tests.*;
 
 /**
 * @author Javier Paniza
 */
 
 public class WarehouseTest extends ModuleTestBase {
 
 public WarehouseTest(String testName) {
 super(testName, "Management", "Warehouse"); // 1
 }
 
 public void testCreateReadUpdateDelete() throws Exception {
 // Create
 execute("CRUD.new"); // 2
 setValue("number", "7"); // 3
 setValue("name", "JUNIT Warehouse");
 execute("CRUD.save");
 assertNoErrors(); // 4
 assertValue("number", ""); // 5
 assertValue("name", "");
 
 // Read
 setValue("number", "7");
 execute("CRUD.search");
 assertValue("number", "7");
 assertValue("name", "JUNIT Warehouse");
 
 // Update
 setValue("name", "JUNIT Warehouse MODIFIED");
 execute("CRUD.save");
 assertNoErrors();
 assertValue("number", "");
 assertValue("name", "");
 
 // Verify if modified
 setValue("number", "7");
 execute("CRUD.search");
 assertValue("number", "7");
 assertValue("name", "JUNIT Warehouse MODIFIED");
 
 // Delete
 execute("CRUD.delete");
 assertMessage("Warehouse deleted successfully"); // 6
 }
 
 }
Давайте опишем выше представленный код (номер пункта описания проставлен в строчном комментарии в конце строки кода):
  1. Конструктор: В конструкторе мы сообщаем имя приложение (application name) и имя модуля (module name).
  2. execute: Позволяет иммитировать нажатие кнопки или переход по веб ссылке. В качестве аргумента вы указываете имя действия (action name); список действий вы найдете в OpenXava/xava/default-controllers.xml (предопределенные контроллеры) и Management/xava/controllers.xml (остальные контроллеры). Узнать, какое действие нужно использовать, очень просто. Если навести мышку на ссылку, выполняющую действие, в интернет-броузере, то в строке подсказки можно увидеть название кода JavaScript, который выполняет дейтствие OpenXava. Используемый в нашем примере execute(“CRUD.new”) соответствует нажатию кнопки 'new' (Добавить новую запись) в пользовательском интерфейсе.
  3. setValue: Присваивает значение полю веб формы. Результат выполнения setValue(“name”, “Pepe”) такой же, как если бы пользователь ввел в поле 'name' текст “Pepe” в пользовательском интерфейсе. Значения всегда должны те же, что должны вводиться в форме HTML.
  4. assertNoErrors: Проверяет, что не возникло ошибок. В пользовательском интерфейсе OX сообщения об ошибке выводятся в виде красных сообщений в рамке и могут добавляться логикой приложения.
  5. assertValue: Проверяет, что значение поля формты соответствует заданному.
  6. assertMessage: Проверяет, что приложение выводит заданное информационное сообщение.
Как вы увидели, написать тест для тестирования вашего модуля чрезвычайно просто. Написание стандартного кода занимает не больше 5 минут,а результатом может оказаться экономия многих часов на более поздних фазах проекта из-за того, что у вас не будет необходимость вручную тестировать - проверять функциональность вашего модуля, а автоматическая проверка займет буквально 1 секунду. И если в результате последующих изменений (в т.ч. произведённых в других частях приложения) модуль Warehouse перестанет работать, то запуск теста сразу предупредит вас об этом.
Более детальную информацию вы найдете в JavaDoc API в описании org.openxava.tests.ModuleTestBase, также рекомендуем посмотреть примеры в пакете org.openxava.test.tests проекта OpenXavaTest, поставляемого с дистрибутивом OX.
По-умолчанию тесты выполняются над модулем в (alone) непортальном режиме (т.е. развернутом задачей deployWar). Если вам необходимо протестировать портальную версию модуля (она формируется задачей generatePortlets), то вам необходимо отредактировать properties/xava-junit.properties, установив:
 liferay.url=web/guest
Это вариант конфигурации для тестирования портлета в портале Liferay. Также возможно тестирование для портала JetSpeed2, изучите OpenXavaTest/properties/xava-junit.properties, если вам нужна эта возможность.

Интернационализация

Теперь, когда наше приложение наконец заработало, осталось завершить один маленький штрих. Современное бизнес-приложение должно поддерживать интернационализацию - возможность перевода интерфейса приложения на другие языки и ввода информации на разных языках. С последним проблем нет - если вы используете UTF-8 как кодовую страницу, а это кодировка используется Java по-умолчанию.
Данный раздел посвящен интернализации именно интерфейса приложения. OX имеет встроенную поддержку интернационализации интерфейса приложения. OX поддерживает работу с файлами сообщений и константыми текстовыми полями (labels) интерфейса. Сообщения и текстовые поля интерфейса размещаются в property-файле, который располагается а папке i18n. В нашем примере файл называется Management-labels_en.properties.Добавьте в файл:
 Warehouse=Warehouse
Вам необязательно добавлять в этот файл все свойства, т.к. большинство часто употребляемых случаев уже включены в OpenXava (например, число (number), имя (name), описание (description) и т.д.) для следующих языков: English, Spanish, Chinese, German, Polish, Indonesian, French, Italian и Catalan.
Если вам хотите перевести интерфейс приложения OX, все, что вам нужно - скопировать файл интернационализации, заменив в названии суффикс _en на суффикс, соответствующий вашей локализации, например, _ru. Для нашего примера получится файл Management-labels_ru.properties со слелующим содержанием:
 Warehouse=Склад
Стандартные метки и сообщения OpenXava помещены в файлы OpenXava/i18n/Labels.properties и OpenXava/i18n/Messages.properties, соответственно. Если вы хотите их перевести на ваш язык, не нужно редактировать данные файлы. Необходимо добавить переводимые метки и сообщения в файлы вашего проекта (эта возможность появилась с версии v2.0.3 OX). Например, если вы хотите заменить стандартное сообщение о количестве записей в режиме List ''There are 23663 objects in list” (это пример), вам необходимо добавить в Management-messages_en.properties следующую строку:
 # list_count is in Messages_en.properties of OpenXava, this is an example
 # of overriding a standard openxava message
 list_count={0} записей в списке
Теперь ваше приложение выведет “23663 записей в списке” вместо стандратного сообщения OpenXava “'There are 23663 objects in list”.
Примеры того, как определять метки и сообщения, вы найдете в папке OpenXavaTest/i18n.